<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>存取属性描述符</title>
  <!-- 
  在JavaScript中，存取属性描述符（Accessor Property Descriptor）用于定义对象的访问器属性，这些属性通过 getter 和 setter 方法来访问和修改。访问器属性描述符允许开发者在访问属性时执行特定的操作，如计算值或验证输入。
  一、存取属性描述符的组成
  存取属性描述符主要有以下三个特性：
  1. get：
    - 一个函数，当访问该属性时会被调用。它用于计算属性的值。

  2. set：
    - 一个函数，当设置该属性时会被调用。它用于定义如何处理对该属性的赋值操作。

  3. enumerable：
    - 一个布尔值，指示属性是否可以在  `for...in`  循环中被枚举。

  4. configurable：
    - 一个布尔值，指示属性是否可以被删除或修改其特性。

  二、创建存取属性描述符
  可以使用  `Object.defineProperty()`  方法来创建或修改对象的存取属性描述符。该方法接受三个参数：目标对象、属性名和属性描述符对象。
  const person = {
      firstName: 'John',
      lastName: 'Doe',
      get fullName() {
          return `${this.firstName} ${this.lastName}`; // 计算属性值
      },
      set fullName(name) {
          [this.firstName, this.lastName] = name.split(' '); // 处理赋值操作
      }
  };

  // 访问存取属性
  console.log(person.fullName); // 输出: John Doe

  // 修改存取属性
  person.fullName = 'Jane Smith';
  console.log(person.firstName); // 输出: Jane
  console.log(person.lastName); // 输出: Smith

  三、存取属性的特性
  1. 只读属性：
    - 如果只定义  `get`  方法而不定义  `set`  方法，则该属性为只读属性，无法通过赋值来修改。
    const obj = {
        _value: 42,
        get value() {
            return this._value; // 只读属性
        }
    };

    console.log(obj.value); // 输出: 42
    obj.value = 100; // 无法修改，且不会报错
    console.log(obj.value); // 仍然输出: 42
  2. 可枚举和可配置：
    - 存取属性的  `enumerable`  和  `configurable`  特性与数据属性相同，可以通过设置这两个属性来控制属性的可见性和可修改性。
    const obj = {};
    Object.defineProperty(obj, 'name', {
        get() {
            return 'Alice';
        },
        enumerable: false, // 不可枚举
        configurable: true // 可配置
    });

    console.log(obj.name); // 输出: Alice
    console.log(Object.keys(obj)); // 输出: [] (name 不在可枚举属性中)

  四、总结
  - 存取属性描述符用于定义通过 getter 和 setter 方法访问和修改对象属性的行为。
  - 可以使用  `Object.defineProperty()`  方法创建存取属性描述符。
  - 存取属性可以是只读的，也可以是可读可写的，具体取决于是否定义了  `set`  方法。
  - 理解存取属性描述符有助于创建更灵活和强大的对象，允许在访问和修改属性时执行自定义逻辑。
   -->
</head>
<body>

  <script>
    // 1. 定义一个对象
    const person = {
        firstName: 'Jane',
        lastName: 'Smith',
        get fullName() {
            return `${this.firstName} ${this.lastName}`;
        },
        set fullName(name) {
            const parts = name.split(' ');
            this.firstName = parts[0];
            this.lastName = parts[1];
        }
    };

    // 访问存取属性
    console.log(person.fullName); // 输出: Jane Smith

    // 修改存取属性
    person.fullName = 'John Doe';

    // 2. vue2响应式原理
    const obj = {
      name: 'Alice',
    }

    //  对obj对象中的name添加描述符(存取属性描述符)
    let _name = ""
    Object.defineProperty(obj, 'name', {
      configurable: true, // 可配置
      enumerable: true, // 可枚举
      get() {
        console.log("get方法被调用了")
        return _name;
      },
      set(value) {
        console.log("set方法被调用了", value)
        _name = value;
      },
    })

    obj.name = "Bob";
    console.log(obj.name);
    
  </script>
  
</body>
</html>